﻿namespace Warehouse

open System
open System.Data.Entity.Design.PluralizationServices
open System.Globalization
open System.Data
open System.Data.Objects.DataClasses
open FSharp.Windows

[<AbstractClass>]
[<AllowNullLiteral>]
type EntityModel<'TEntity when 'TEntity :> EntityObject and 'TEntity : (new : unit -> 'TEntity) and 'TEntity : null and 'TEntity : equality>() = 
    inherit Model()

    static let entitySetName = PluralizationService.CreateService(CultureInfo("en-US")).Pluralize(typeof<'TEntity>.Name)

    [<DefaultValue>]
    val mutable Entity : 'TEntity

    member this.IsNewEntity = this.Entity = null

    abstract Init : unit -> unit
    abstract Flush : unit -> unit
    abstract Compute : unit -> unit
    default this.Compute() = ()

    static member Load<'TEntityModel when 'TEntityModel :> EntityModel<'TEntity> and 'TEntityModel : not struct>(entity : 'TEntity) =
        if entity = null then nullArg "existingEntity"
        let model = Model.Create<'TEntityModel>()
        model.Entity <- entity
        model.Init()
        model.Compute()
        model

    member this.UpdateEntity() =
        assert this.IsValid
        if this.IsNewEntity then this.Entity <- new 'TEntity()
        this.Flush()

    member this.DiscardChanges() =
        assert not this.IsNewEntity 
        this.Init()

    member this.SaveEntity(repository : DataModel.Repository) =
        assert this.IsValid
        if this.Entity = null || this.Entity.EntityState = EntityState.Unchanged 
        then 
            this.UpdateEntity()
        if this.Entity.EntityState = EntityState.Detached 
        then 
            repository.AddObject(entitySetName, this.Entity)

        let recordsAffected = repository.SaveChanges()
        assert (recordsAffected > 0)

    member this.DeleteEntity(repository : DataModel.Repository) =
        if this.Entity <> null
        then 
            repository.DeleteObject this.Entity

